package org.infodavid.common.persistence.impl;

import java.util.HashMap;
import java.util.Map;

import javax.persistence.PersistenceException;

import org.apache.commons.lang.StringUtils;
import org.infodavid.common.model.impl.AbstractDataObjectImpl;
import org.infodavid.common.persistence.ConnectionHelperRegistry;
import org.infodavid.common.persistence.IConnectionConfiguration;
import org.infodavid.common.persistence.IDatabaseHost;
import org.infodavid.common.persistence.IDatabaseSchema;

/**
 * The Class DatabaseHostImpl.
 */
public class DatabaseHostImpl extends AbstractDataObjectImpl<Long> implements IDatabaseHost {

  /** serialVersionUID. */
  private static final long serialVersionUID = -6474625515242390307L;

  /** The hostname. */
  private String hostname;

  /** The name. */
  private String name;

  /** The IP address. */
  private String ipAddress;

  /** The comment. */
  private String comment;

  /** The driver. */
  private String jdbcDriver;

  /** The user password. */
  private String password;

  /** The user name. */
  private String username;

  /** The type. */
  private String type;

  /** The TCP port. */
  private Integer tcpPort;

  /** The schemas. */
  private Map<String,IDatabaseSchema> schemas;

  /** The new schema allowed flag. */
  private boolean newSchemaAllowed = true;

  /** The locked flag. */
  private boolean locked = false;

  /**
   * constructor.
   * @throws Exception the exception
   */
  public DatabaseHostImpl() throws Exception {
    super();
  }

  /**
   * constructor.
   * @param keyArg the key
   * @throws Exception the exception
   */
  public DatabaseHostImpl(final Long keyArg) throws Exception {
    super();

    setKey(keyArg);
  }

  /*
   * See super class or interface. (non-Javadoc)
   * @see org.infodavid.common.model.impl.DataObjectImpl#init()
   */
  @Override
  public void init() throws Exception {
    super.init();

    locked = false;
    newSchemaAllowed = true;
    hostname = null;
    jdbcDriver = null;
    name = null;
    password = null;
    username = null;
    type = null;
    comment = null;
    schemas = new HashMap<String,IDatabaseSchema>();
  }

  /*
   * (non-Javadoc)
   * @see org.infodavid.common.persistence.IDatabaseHost#isLocked()
   */
  @Override
  public boolean isLocked() {
    return locked;
  }

  /*
   * (non-Javadoc)
   * @see org.infodavid.common.persistence.IDatabaseHost#isNewSchemaAllowed()
   */
  @Override
  public boolean isNewSchemaAllowed() {
    return newSchemaAllowed;
  }

  /*
   * See super class or interface. (non-Javadoc)
   * @see org.infodavid.common.persistence.IDatabaseHost#getHostname()
   */
  @Override
  public String getHostname() {
    return hostname;
  }

  /*
   * See super class or interface. (non-Javadoc)
   * @see org.infodavid.common.persistence.IDatabaseHost#getName()
   */
  @Override
  public String getName() {
    return name;
  }

  /*
   * See super class or interface. (non-Javadoc)
   * @see org.infodavid.common.persistence.IDatabaseHost#getIpAddress()
   */
  @Override
  public String getIpAddress() {
    return ipAddress;
  }

  /*
   * See super class or interface. (non-Javadoc)
   * @see org.infodavid.common.persistence.IDatabaseHost#getPassword()
   */
  @Override
  public String getPassword() {
    return password;
  }

  /*
   * See super class or interface. (non-Javadoc)
   * @see org.infodavid.common.persistence.IDatabaseHost#getUsername()
   */
  @Override
  public String getUsername() {
    return username;
  }

  /*
   * See super class or interface. (non-Javadoc)
   * @see org.infodavid.common.persistence.IDatabaseHost#getType()
   */
  @Override
  public String getType() {
    return type;
  }

  /*
   * See super class or interface. (non-Javadoc)
   * @see org.infodavid.common.persistence.IDatabaseHost#getTcpPort()
   */
  @Override
  public Integer getTcpPort() {
    return tcpPort;
  }

  /*
   * See super class or interface. (non-Javadoc)
   * @see org.infodavid.common.persistence.IDatabaseHost#getJdbcDriver()
   */
  @Override
  public String getJdbcDriver() {
    return jdbcDriver;
  }

  /*
   * See super class or interface. (non-Javadoc)
   * @see org.infodavid.common.persistence.IDatabaseHost#setHostname(java.lang.String)
   */
  @Override
  public void setHostname(final String value) {
    if (!equals(hostname, value)) {
      final Object old = hostname;
      hostname = value;
      markModified(HOST, old, hostname);
    }
  }

  /*
   * See super class or interface. (non-Javadoc)
   * @see org.infodavid.common.persistence.IDatabaseHost#setIpAddress(java.lang.String)
   */
  @Override
  public void setIpAddress(final String value) {
    if (!equals(ipAddress, value)) {
      final Object old = ipAddress;
      ipAddress = value;
      markModified(IP_ADDRESS, old, ipAddress);
    }
  }

  /*
   * See super class or interface. (non-Javadoc)
   * @see org.infodavid.common.persistence.IDatabaseHost#setJdbcDriver(java.lang.String)
   */
  @Override
  public void setJdbcDriver(final String value) {
    if (!equals(jdbcDriver, value)) {
      final Object old = jdbcDriver;
      jdbcDriver = value;
      markModified(JDBC_DRIVER, old, jdbcDriver);
    }
  }

  /**
   * Sets the type.
   * @param value the type
   */
  @Override
  public void setType(final String value) {
    if (!equals(type, value)) {
      final Object old = type;
      type = value;
      markModified(TYPE, old, type);
    }
  }

  /*
   * See super class or interface. (non-Javadoc)
   * @see org.infodavid.common.persistence.IDatabaseHost#setTcpPort(java.lang.Integer)
   */
  @Override
  public void setTcpPort(final Integer value) {
    if (!equals(tcpPort, value)) {
      final Object old = tcpPort;
      tcpPort = value;
      markModified(TCP_PORT, old, tcpPort);
    }
  }

  /*
   * See super class or interface. (non-Javadoc)
   * @see org.infodavid.common.persistence.IDatabaseHost#setName(java.lang.String)
   */
  @Override
  public void setName(final String value) {
    if (!equals(name, value)) {
      final Object old = name;
      name = value;
      markModified(NAME, old, name);
    }
  }

  /*
   * See super class or interface. (non-Javadoc)
   * @see org.infodavid.common.persistence.IDatabaseHost#setPassword(java.lang.String)
   */
  @Override
  public void setPassword(final String value) {
    if (!equals(password, value)) {
      final Object old = password;
      password = value;
      markModified(PASSWORD, old, password);
    }
  }

  /*
   * See super class or interface. (non-Javadoc)
   * @see org.infodavid.common.persistence.IDatabaseHost#setUsername(java.lang.String)
   */
  @Override
  public void setUsername(final String value) {
    if (!equals(username, value)) {
      final Object old = username;
      username = value;
      markModified(USERNAME, old, username);
    }
  }

  /*
   * See super class or interface. (non-Javadoc)
   * @see org.infodavid.common.persistence.IDatabaseHost#getSchemas()
   */
  @Override
  public Map<String,IDatabaseSchema> getSchemas() {
    return schemas;
  }

  /*
   * See super class or interface. (non-Javadoc)
   * @see org.infodavid.common.persistence.IDatabaseHost#addSchema(IDatabaseSchema)
   */
  @Override
  public void addSchema(final IDatabaseSchema value) {
    schemas.put(value.getName(), value);
  }

  /*
   * See super lass or interface. (non-Javadoc)
   * @see org.infodavid.common.persistence.IDatabaseHost#removeSchema(IDatabaseSchema)
   */
  @Override
  public boolean removeSchema(final IDatabaseSchema value) {
    return schemas.remove(value.getName()) == value;
  }

  /*
   * See super class or interface. (non-Javadoc)
   * @see org.infodavid.common.model.ICommented#getComment()
   */
  @Override
  public String getComment() {
    return comment;
  }

  /*
   * See super class or interface. (non-Javadoc)
   * @see org.infodavid.common.model.ICommented#setComment(java.lang.String)
   */
  @Override
  public void setComment(final String value) {
    if (!equals(comment, value)) {
      final Object old = comment;
      comment = value;
      markModified(COMMENT, old, comment);
    }
  }

  /**
   * Sets the schemas.
   * @param values the schemas
   */
  public void setSchemas(final Map<String,IDatabaseSchema> values) {
    if (!equals(schemas, values)) {
      final Object old = schemas;
      schemas = values;
      markModified(SCHEMAS, old, schemas);
    }
  }

  /*
   * See super class or interface. (non-Javadoc)
   * @see org.infodavid.common.persistence.IDatabaseHost#setNewSchemaAllowed(boolean)
   */
  @Override
  @SuppressWarnings("boxing")
  public void setNewSchemaAllowed(final boolean flag) {
    if (!equals(newSchemaAllowed, flag)) {
      final Object old = newSchemaAllowed;
      newSchemaAllowed = flag;
      markModified(NEW_SCHEMA_ALLOWED, old, newSchemaAllowed);
    }
  }

  /*
   * See super class or interface. (non-Javadoc)
   * @see org.infodavid.common.persistence.IDatabaseHost#setLocked(boolean)
   */
  @Override
  @SuppressWarnings("boxing")
  public void setLocked(final boolean flag) {
    if (!equals(locked, flag)) {
      final Object old = locked;
      locked = flag;
      markModified(LOCKED, old, locked);
    }
  }

  /*
   * See super class or interface. (non-Javadoc)
   * @see org.infodavid.common.model.impl.DataObjectImpl#toString(java.lang.StringBuffer)
   */
  @Override
  protected StringBuffer toString(final StringBuffer builder) {
    super.toString(builder);

    builder.append(" [comment=");
    builder.append(comment);
    builder.append(", hostname=");
    builder.append(hostname);
    builder.append(", ipAddress=");
    builder.append(ipAddress);
    builder.append(", jdbcDriver=");
    builder.append(jdbcDriver);
    builder.append(", name=");
    builder.append(name);
    builder.append(", password=");

    if (password == null) {
      builder.append("null");
    }
    else {
      builder.append(password.replace(".*", "#"));
    }

    builder.append(", schemas=");
    builder.append(schemas);
    builder.append(", type=");
    builder.append(type);
    builder.append(", username=");
    builder.append(username);
    builder.append(", locked=");
    builder.append(locked);
    builder.append(", newSchemaAllowed=");
    builder.append(newSchemaAllowed);
    builder.append("]");

    return builder;
  }

  /*
   * See super class or interface. (non-Javadoc)
   * @see org.infodavid.common.persistence.IDatabaseHost#toConnectionConfiguration()
   */
  @Override
  public IConnectionConfiguration toConnectionConfiguration() throws PersistenceException {
    final IConnectionConfiguration configuration;

    configuration = new ConnectionConfigurationImpl();

    configuration.setName(getName());
    configuration.setTcpPort(getTcpPort());

    if (StringUtils.isEmpty(getIpAddress())) {
      configuration.setHost(getName());
    }
    else {
      configuration.setHost(getIpAddress());
    }

    configuration.setJdbcDriver(getJdbcDriver());
    configuration.setPassword(getPassword());
    configuration.setType(getType());
    configuration.setUser(getUsername());
    configuration.setStdConnectionString(ConnectionHelperRegistry.getInstance()
        .getConnectionString(configuration));

    return configuration;
  }

  /*
   * (non-Javadoc)
   * @see org.infodavid.common.model.impl.DataObjectImpl#hashCode()
   */
  @Override
  public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + (getHostname() == null ? 0 : getHostname().hashCode());

    return prime * result + (getIpAddress() == null ? 0 : getIpAddress().hashCode());
  }

  /*
   * (non-Javadoc)
   * @see org.infodavid.common.model.impl.DataObjectImpl#equals(java.lang.Object)
   */
  @Override
  public boolean equals(final Object obj) {
    if (this == obj) {
      return true;
    }

    if (obj == null) {
      return false;
    }

    if (!(obj instanceof IDatabaseHost)) {
      return false;
    }

    final IDatabaseHost other = (IDatabaseHost)obj;

    if (getHostname() == null) {
      if (other.getHostname() != null) {
        return false;
      }
    }
    else if (!getHostname().equals(other.getHostname())) {
      return false;
    }

    if (getIpAddress() == null) {
      if (other.getIpAddress() != null) {
        return false;
      }
    }
    else if (!getIpAddress().equals(other.getIpAddress())) {
      return false;
    }

    return true;
  }
}
